2025년 9월 14일 일요일
n8n용 실전 워크플로우: 서비스계정(서비스 계정 토큰)으로 Google apal(Gemini) 호출하고 Gmail/Sheets로 처리하기
실전 튜토리얼 — n8n에 Import 가능한 Gemini(apal) 워크플로우 + 서비스계정 인증 가이드
요약: 이 글은 n8n에 바로 Import 가능한 JSON 워크플로우( Webhook → Gemini 호출 → 응답 추출 → Gmail 발송 → Google Sheets 기록 )와, 서비스계정 기반 인증(토큰 발급 방법: gcloud, Node 스크립트)을 단계별로 설명합니다. 워크플로우는 API 키 대신 서비스계정에서 발급한 Access Token(짧은 수명)을 사용하도록 설계되어 있습니다.
1) 준비물
- n8n 계정(클라우드 또는 자체 호스팅)
- Google Cloud 프로젝트
- 서비스 계정(Service Account) JSON 키 파일 (roles: access to Generative API + Sheets + Gmail 필요)
- gcloud CLI (테스트용 토큰 발급 시 권장) 또는 Node.js(자동화 스크립트용)
- n8n에서 Gmail/Google Sheets 크레덴셜 설정 (OAuth 방식 또는 서비스 계정 연동)
2) 핵심 아이디어(동작 흐름)
- 외부에서 Webhook 호출 → n8n 워크플로우 시작
- 서비스 계정으로 Access Token 발급(수동 혹은 자동화 방식)
- HTTP Request 노드로 Gemini(apal) REST API 호출(Authorization: Bearer <ACCESS_TOKEN>)
- Function 노드로 응답 추출 및 포맷
- Gmail 노드로 발송, Google Sheets 노드로 발송 로그 저장
3) n8n Import용 워크플로우 JSON
아래 JSON을 그대로 복사 → n8n UI에서 Import from file/clipboard로 불러오세요. (노드 내에 있는 REPLACE_WITH_ACCESS_TOKEN
자리표시자를 실제 Access Token 또는 n8n 환경변수로 바꿔주세요)
{
"name": "Gemini ServiceAccount Workflow (Webhook → Gemini → Gmail → Sheets)",
"nodes": [
{
"parameters": {
"path": "gemini-serviceagent",
"responseMode": "lastNode",
"options": {}
},
"id": "1",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [240, 260]
},
{
"parameters": {
"url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-latest:generateContent",
"method": "POST",
"authentication": "headerAuth",
"headerAuth": {
"name": "Authorization",
"value": "Bearer REPLACE_WITH_ACCESS_TOKEN"
},
"jsonParameters": true,
"options": {},
"body": {
"contents": [
{
"parts": [
{
"text": "You are an assistant. Given the user request, produce a concise reply in markdown. Input: {{$json.body.inputText || $json.inputText || $json.query || 'No input provided.'}}"
}
]
}
],
"generation_config": {
"max_output_tokens": 400
}
}
},
"id": "2",
"name": "Gemini (HTTP Request)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [560, 260]
},
{
"parameters": {
"functionCode": "const body = items[0].json;\n// 안전하게 구조를 확인하고 텍스트 추출\nlet text = '';\ntry {\n text = body.candidates?.[0]?.content?.parts?.[0]?.text || JSON.stringify(body);\n} catch (e) {\n text = JSON.stringify(body);\n}\nreturn [{ json: { reply: text, raw: body } }];"
},
"id": "3",
"name": "Extract Reply",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [820, 260]
},
{
"parameters": {
"fromEmail": "me",
"toEmail": "{{$json.body?.email || $json.email || 'recipient@example.com'}}",
"subject": "自动发出: Gemini 에이전트 응답",
"text": "{{$json.reply}}",
"additionalFields": {}
},
"id": "4",
"name": "Gmail Send",
"type": "n8n-nodes-base.gmail",
"typeVersion": 1,
"position": [1080, 180]
},
{
"parameters": {
"operation": "append",
"sheetId": "REPLACE_WITH_SHEET_ID",
"sheetRange": "Sheet1!A:C",
"options": {},
"columns": [
{
"column": "A",
"value": "={{$now}}"
},
{
"column": "B",
"value": "={{$json.reply}}"
},
{
"column": "C",
"value": "={{$json.raw && JSON.stringify($json.raw).slice(0,200)}}"
}
]
},
"id": "5",
"name": "Google Sheets Append",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 1,
"position": [1080, 340]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Gemini (HTTP Request)",
"type": "main",
"index": 0
}
]
]
},
"Gemini (HTTP Request)": {
"main": [
[
{
"node": "Extract Reply",
"type": "main",
"index": 0
}
]
]
},
"Extract Reply": {
"main": [
[
{
"node": "Gmail Send",
"type": "main",
"index": 0
},
{
"node": "Google Sheets Append",
"type": "main",
"index": 0
}
]
]
}
}
}
설명(중요):
Gemini (HTTP Request)
노드는 Authorization 헤더에 `Bearer REPLACE_WITH_ACCESS_TOKEN`가 들어가 있습니다. 이 자리에 실제 Access Token(예:ya29.<...>
)을 넣거나, n8n의 환경변수/credentials로 대체하세요.Google Sheets Append
의sheetId
를 실제 스프레드시트 ID로 바꿔야 합니다.Gmail Send
노드는 n8n에서 미리 Gmail credentials를 설정해두어야 정상 작동합니다.
4) 서비스계정으로 Access Token 얻는 방법 (권장: gcloud CLI — 빠르고 안전)
가장 간단한 방법(테스트용)은 gcloud
CLI를 사용하는 것입니다. 아래는 로컬에서 토큰을 얻는 방법입니다.
# 1) 서비스 계정 키 파일로 gcloud에 인증 (한 번만)
gcloud auth activate-service-account --key-file="/path/to/service-account.json"
# 2) Access Token 발급 (짧은 유효기간 토큰)
gcloud auth print-access-token
# 출력 예시:
# ya29.a0AfH6SMB... (이를 n8n HTTP Request의 Authorization 헤더에 넣으세요)
토큰은 일반적으로 ~1시간
정도 유효합니다. 운영 환경에서는 토큰을 주기적으로 재발급하거나 자동 갱신 로직을 구현해야 합니다.
5) 서비스계정 토큰 자동화 (Node.js 스크립트 예제)
운영에서 매번 수동으로 토큰을 붙여넣기보다, 다음과 같은 작은 서비스(또는 n8n 내부의 Function
→ HTTP Request
조합)를 사용해 토큰을 자동으로 갱신하고 워크플로우 실행 시 최신 토큰을 주입하는 방법이 좋습니다. 아래는 Node.js에서 google-auth-library
를 사용해 액세스 토큰을 얻는 예제입니다.
// getAccessToken.js
const { GoogleAuth } = require('google-auth-library');
async function getToken() {
const auth = new GoogleAuth({
keyFile: '/path/to/service-account.json',
scopes: ['https://www.googleapis.com/auth/cloud-platform','https://www.googleapis.com/auth/userinfo.email']
});
const client = await auth.getClient();
const accessToken = await client.getAccessToken();
console.log(accessToken.token);
}
getToken().catch(console.error);
이 스크립트를 서버에서 실행하거나, CI/pipeline에서 주기적으로 돌려 n8n의 환경변수 또는 별도 비밀 저장소(예: Vault)에 갱신하면 안전하게 운영할 수 있습니다.
6) n8n에서 토큰을 안전하게 사용하는 방법 (권장 패턴)
- 환경 변수 사용: n8n을 실행하는 환경의 환경변수에
GEMINI_ACCESS_TOKEN
을 저장하고 HTTP Request 노드에서 `Authorization: Bearer {{$env.GEMINI_ACCESS_TOKEN}}`로 참조. - 외부 시크릿 스토어: HashiCorp Vault, AWS Secrets Manager 등에서 토큰을 관리하고 n8n에서 주기적으로 가져옴.
- 자동 갱신 워크플로우: 별도 n8n 워크플로우로 토큰 발급(예: Node 스크립트 호출 → token 변수에 저장) 후 주 워크플로우에서 참조.
7) Gmail/Sheets 크레덴셜 구성 팁
- Gmail 노드: n8n의 OAuth2 연결을 사용하세요(개인 Gmail 테스트 시 'me'로 사용 가능). 프로덕션에서는 G Suite(Workspace) 서비스 계정을 통한 도메인 권한 위임(delegation) 구성 권장.
- Google Sheets: 서비스 계정으로 편집 권한을 준 시트를 사용하면 서비스 계정 기반 접근이 가능합니다. 서비스 계정 이메일을 시트 공유 대상에 추가하세요.
8) 테스트 & 운영 체크리스트
- Webhook을 호출하여 전체 플로우가 동작하는지 확인
- Gemini 응답 구조(
candidates → content → parts → text
)가 예상대로인지 확인 - 토큰 만료 시 자동 갱신 로직 작동 여부 확인
- Sheets에 로그가 정상 기록되는지(중복/포맷) 확인
- Gmail 발송 성공 여부와 스팸 처리를 모니터링
9) 다음 단계 제안
원하시면 제가 아래 작업을 바로 해드릴게요:
- ① 위 JSON에서
REPLACE_WITH_ACCESS_TOKEN
을 자동으로 갱신해 넣는 n8n 워크플로우(토큰 발급 워크플로우) 생성 - ② Gmail 발송 템플릿(HTML) 자동화 및 이메일 구독자 필드 연동
- ③ 서비스 계정 범위(roles) 최소화와 IAM 설정 가이드 문서 작성